use actix_web::{HttpRequest, web};

use common::error::MyError;
use common::header::Authorization;
use entity::user;
use model::user::{CreateUser, ResetPassword, SetUerRole, UserPage};
use security::bcrypt::{hash_context, verify_context};
use security::ctx::destroy_token_by_uid;

use crate::base::BaseService;
use crate::manager::base::BaseManager;
use crate::manager::role::RoleManager;
use crate::manager::user::UserManager;

pub struct UserService {}

impl BaseService<i64, user::Model, UserPage, CreateUser, user::Model, UserManager> for UserService {
    async fn info(
        user_id: i64,
        _req: &HttpRequest,
        _authorization: web::Header<Authorization>,
    ) -> Result<user::Model, MyError> {
        let mut user = UserManager::info(user_id)
            .await?
            .ok_or(MyError::ServerError(format!(
                "user [{:?}] does not exist",
                user_id
            )))?;
        user.password = None;
        Ok(user)
    }

    async fn update(
        form: user::Model,
        _req: &HttpRequest,
        _authorization: web::Header<Authorization>,
    ) -> Result<i64, MyError> {
        let uid = UserManager::update(form.clone()).await?;
        if form.status.is_some() && !form.status.clone().unwrap() {
            destroy_token_by_uid(&uid)?;
        }
        Ok(uid)
    }

    async fn delete(
        user_id: i64,
        _req: &HttpRequest,
        _authorization: web::Header<Authorization>,
    ) -> Result<bool, MyError> {
        let res = UserManager::delete(user_id).await?;
        if res {
            destroy_token_by_uid(&user_id)?;
            Ok(res)
        } else {
            Ok(res)
        }
    }
}

impl UserService {
    pub async fn get_role(user_id: i64) -> Result<Vec<i64>, MyError> {
        Ok(RoleManager::get_role_ids_by_uid(user_id).await?)
    }

    pub async fn set_role(set_uer_role: SetUerRole) -> Result<bool, MyError> {
        let uid = set_uer_role
            .user_id
            .ok_or(MyError::ServerError("用户id不能为空".to_string()))?;
        let role = set_uer_role
            .role
            .ok_or(MyError::ServerError("角色不能为空".to_string()))?;
        Ok(RoleManager::set_user_role(uid, role).await?)
    }

    pub async fn reset_password(reset_password: ResetPassword) -> Result<bool, MyError> {
        let uid = reset_password
            .user_id
            .ok_or(MyError::ServerError("用户id不能为空".to_string()))?;
        let password = reset_password
            .password
            .ok_or(MyError::ServerError("新密码不能为空".to_string()))?;
        let user = UserManager::info(uid).await?;
        match user {
            None => Err(MyError::ServerError("用户不存在".to_string())),
            Some(user) => match user.password {
                None => Err(MyError::ServerError("用户未设置".to_string())),
                Some(user_password) => {
                    if verify_context(&password, user_password)? {
                        Err(MyError::ServerError("新密码与旧密码相同".to_string()))
                    } else {
                        Ok(UserManager::reset_password(uid, hash_context(password)?).await?)
                    }
                }
            },
        }
    }
}
